#include <ncurses.h>
#include <chrono>
#include <thread>
#include <random>
#include "board.hpp"
#include "piece.hpp"

void resetPiece(Piece *&first, Piece *&second, int id)
{
	delete first;
	first = second;
	second = new Piece(id);
}

void swapPiece(Piece *&first, Piece *&second)
{
	second->x = first->x;
	second->y = first->y;
	Piece *swap = nullptr;
	swap = first;
	first = second;
	second = swap;
}

int randomPiece(std::mt19937_64 &gen, int &prev)
{
	std::uniform_int_distribution<> get(0,6);
	int ret = get(gen);
	if(ret == prev)
		ret = get(gen);
	prev = ret;
	return ret;
}

int main()
{
	initscr();
	noecho();
	raw();
	nodelay(stdscr, true);
	curs_set(0);
	start_color();
	if(!has_colors())
	{
		printf("fuck\n");
		return 1;
	}
	init_pair(1, 0, 1);
	init_pair(2, 0, 2);
	init_pair(3, 0, 3);
	init_pair(4, 0, 4);
	init_pair(5, 0, 5);
	init_pair(6, 0, 6);
	init_pair(7, 0, 7);

	Board board;

	std::random_device dev;
	std::mt19937_64 gen(dev());
	std::uniform_int_distribution<> get(0,6);
	int prev = 0;
	prev = randomPiece(gen, prev);
	Piece *buffer = new Piece(prev);
	prev = randomPiece(gen, prev);
	Piece *hold = new Piece(prev);
	Piece *current = new Piece(prev);

	bool clean[20];
	for(int i = 0;i < 20;i++)
		clean[i] = false;
	int input = 0,saveInput = 0;
	double time = 0;
	double maxTime = 1;
	int score = 0;
	auto end = std::chrono::steady_clock::now();
	do
	{
		auto start = end;
		input = getch();
		if(input == 119)
			current->rotate(true);
		else if(input == 100)
			current->x++;
		else if(input == 97)
			current->x--;
		else if(input == 115)
			time+=maxTime;
		else if(input == 32)
			swapPiece(current, hold);
		if(input != -1)
			saveInput = input;

		if(time > maxTime)
			current->y++;	
		bool overlap = false;
		for(int y = 0;y < 4;y++)
			for(int x = 0;x < 4;x++)
				if((current->get(y,x) != 0 && board.get(current->y+y,current->x+x) != 0)
						|| current->y > 16)
					overlap = true;
		if(overlap)
		{
			if(time > maxTime)
			{
				current->y--;
				for(int y = 0;y < 4;y++)
					for(int x = 0;x < 4;x++)
						if(current->get(y,x) != 0)
						{
							if(board.get(current->y+y,current->x+x) != 0) 
								input = 27;
							board.set(current->y+y,current->x+x,current->get(y,x));
						}
				resetPiece(current, buffer, randomPiece(gen, prev));
			}
			if(saveInput == 100)
				current->x--;
			else if(saveInput == 97)
				current->x++;
			else if(saveInput == 119)
				current->x--;
		}
		if(time > maxTime)
			time -= maxTime;
		for(int y = 0;y < 4;y++)
			for(int x = 0;x < 4;x++)
			{
				if(current->get(y,x) != 0 && current->x+x < 0)
					current->x = 0-x;
				if(current->get(y,x) != 0 && current->x+x >= 10)
					current->x = 9-x;
			}

		int bufferScore = 0;
		for(int i = 19;i >= 0;i--)
			if(board.test(i))
			{
				board.clean(i);
				bufferScore++;
				maxTime = maxTime*0.9;
			}
		score += ((bufferScore>0)?(bufferScore*200-100):0);

		for(int y = 0;y < 20;y++)
		{
			attron(COLOR_PAIR(7));
			mvprintw(y,9," ");
			mvprintw(y,30," ");
			attroff(COLOR_PAIR(7));
			for(int x = 0;x < 10;x++)
			{
				attron(COLOR_PAIR(board.get(y,x)));
				mvprintw(y,x*2+10,"  ");
				attroff(COLOR_PAIR(board.get(y,x)));
			}
		}

		for(int y = 0;y < 4;y++)
			for(int x = 0;x < 4;x++)
			{
				if(current->get(y,x) != 0)
				{
					attron(COLOR_PAIR(current->get(y,x)));
					mvprintw(current->y+y,(current->x+x)*2+10,"  ");
					attroff(COLOR_PAIR(current->get(y,x)));
				}
				attron(COLOR_PAIR(buffer->get(y,x)));
				mvprintw(y+2,x*2,"  ");
				attroff(COLOR_PAIR(buffer->get(y,x)));
				attron(COLOR_PAIR(hold->get(y,x)));
				mvprintw(y+9,x*2,"  ");
				attroff(COLOR_PAIR(hold->get(y,x)));
			}

		mvprintw(0,2,"Buffer");
		mvprintw(7,3,"Hold");
		mvprintw(0,40,"%d",score);
		end = std::chrono::steady_clock::now();
		std::chrono::duration<double> frame = end-start;
		time+=frame.count();
		refresh();
	}while(input != 27);

	endwin();

	return 0;
}
